package cs271.hw5;


import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.PriorityQueue;

public class CheckoutLine {
	
//	private PriorityQueue<Customer> simulationQueue;
	// this list contains all the customer who will enter the line at their specific arrival times. 
	private List<Customer> customerList  = new ArrayList<Customer>();
	private Scheduler scheduler;
	//this list currently maintains the customer to be processed currently in the line.
	private List<Customer> qList = new ArrayList<Customer>();
	
	private int currentTime = -1;
	
	// the time instant when the scheduler must be worked upon to process another customer.
	private int schCheckTime = -1;
	private Customer lastCustomer;
	private static final int CYCLE_PROCESS_TIME = 10;
	
	public CheckoutLine(Scheduler scheduler) {
		this.scheduler = scheduler;
	}
	
	public void addCustomer(Customer c) {
//		simulationQueue.add(c);
		customerList.add(c);
	}
	
	
	public List<Customer> getCustomerList() {
		return customerList;
	}
	
	
	public static void main(String[] args) {
		CheckoutLine line = new CheckoutLine(new SimpleScheduler());
		populateTestData(line);
		
		line.process(line);
		
		System.out.println("End of Program");
	}	

	
	private static void populateTestData(CheckoutLine line) {
		line.addCustomer(new Customer(1, 25, 1, "c1"));
		line.addCustomer(new Customer(1, 10, 2, "c3"));
		line.addCustomer(new Customer(3, 45, 0, "c2"));
		line.addCustomer(new Customer(3, 5, 3, "c4"));
		line.addCustomer(new Customer(25, 10, 5, "c5"));
	}
	
	
	public void process(CheckoutLine line){

		while(!customerList.isEmpty()){
			currentTime++;
			System.out.println("Current time is " + currentTime);			
			// at every instant, add the incoming customers to the line.
			Iterator itr = customerList.iterator();
			while(itr.hasNext()){
				Customer c = (Customer)itr.next();
				if(c.getArrivalTime() == currentTime){
					System.out.println("Customer " + c.getCustomerName() + " arrived at time " + currentTime);
					qList.add(c);
				}
			}
			
			
			if(schCheckTime == currentTime){
				Customer c1 = (Customer) scheduler.pop();
				c1.setLastProcessTime(currentTime);
				if(c1.getLengthOfCheckout() <= CYCLE_PROCESS_TIME){
					System.out.println("Finished processing customer " + c1.getCustomerName() + " at time " + currentTime);
					qList.remove(c1);
					customerList.remove(c1);
					lastCustomer = null;
				}else{
					lastCustomer = c1;
					c1.setLengthOfCheckout(c1.getLengthOfCheckout() - CYCLE_PROCESS_TIME);
					System.out.println("1 Cycle Finished. Removing customer " + c1.getCustomerName() + " from scheduler.");
				}
			}
			
			//add the customer to the scheduler if it is empty.
			if(scheduler.isEmpty() && !qList.isEmpty()){
				//select customer to process from the qList
				Customer c = getCustomerToProcess();
				System.out.println("Adding Customer " + c.getCustomerName() + " to the Scheduler at time " + currentTime + " .");
				scheduler.push(c);
				int custCheckOutTime = c.getLengthOfCheckout();
				if(custCheckOutTime > CYCLE_PROCESS_TIME){
					schCheckTime = currentTime + CYCLE_PROCESS_TIME;
				}else{
					schCheckTime = currentTime + custCheckOutTime;
				}
				System.out.println("The scheduler to be next processed at time " + schCheckTime);
			}
		}
	}
	
	public Customer getCustomerToProcess(){
		Customer cust;
		List waitTimeCustomerList = new ArrayList();
		if(qList.size() == 1){
			// only 1 customer in the qlist....so process it.
			cust = qList.get(0);
			System.out.println("Only 1 customer " + cust.getCustomerName() + " in the line...so processing this customer.");
		}else{
			if(lastCustomer != null){
				// temporarily remove the last customer so that it is not processed currently.
				qList.remove(lastCustomer);
			}
			//otherwise select customer based on wait time.
			int waitTime = -1;
			int index = 0;
			int len = qList.size();
			for(int i=0; i<len; i++){
				Customer c = (Customer)qList.get(i);
				if(waitTime == -1){
					waitTime = c.getWaitTime(currentTime);
				}else if(c.getWaitTime(currentTime) > waitTime){
					waitTime = c.getWaitTime(currentTime);
					index = i;
				}
			}
			cust = qList.get(index);
			waitTimeCustomerList.add(cust);
			//checking if more than 1 customer has the same wait time.
			for(int i=0; i<qList.size(); i++){
				if(i != index){
					Customer c = (Customer)qList.get(i);
					if(c.getWaitTime(currentTime) == waitTime){
						waitTimeCustomerList.add(c);
					}
				}
			}
			if(waitTimeCustomerList.size() > 1){
				// if more than 1 customer has the same wait time, need to sort upon the priority.
				int priority = -1;
				for(int i=0; i< waitTimeCustomerList.size(); i++){
					Customer c = (Customer) waitTimeCustomerList.get(i);
					System.out.println("Customer " + c.getCustomerName() + " has wait time: " + c.getWaitTime(currentTime));
					if(priority == -1){
						priority = c.getPriority();
					}else if(c.getPriority() < priority){
						priority = c.getPriority();
						index = i;
					}					
				}
				cust = (Customer)waitTimeCustomerList.get(index);
				System.out.println("Selected customer " + cust.getCustomerName() + " based on priority.");				
			}else{
				System.out.println("Selected customer " + cust.getCustomerName() + " based on wait time.");
			}
			if(lastCustomer != null){
				// add the last customer back.
				qList.add(lastCustomer);
			}			
		}
		return cust;
	}
	
	
}




